/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.geotools.tutorial;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.MultiLineString;
import com.vividsolutions.jts.geom.Point;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.util.Collection;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import org.geotools.data.FeatureSource;
import org.geotools.data.collection.ListFeatureCollection;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.data.store.EmptyFeatureCollection;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.DefaultFeatureCollection;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureCollections;
import org.geotools.feature.collection.AbstractFeatureVisitor;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureImpl;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.graph.path.Path;
import org.geotools.graph.structure.Edge;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.styling.StyleFactory;
import org.geotools.swing.JMapPane;
import org.geotools.swing.action.SafeAction;
import org.geotools.swing.event.MapMouseEvent;
import org.geotools.swing.tool.CursorTool;
import org.opengis.feature.Feature;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.NoSuchAuthorityCodeException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import org.opengis.referencing.operation.TransformException;
import org.geotools.styling.Rule;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.NamedStyle;
import org.geotools.styling.Style;
import org.geotools.swing.JMapFrame;
import org.geotools.swing.ProgressWindow;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory2;

import org.geotools.geosearch.Guide;
/**
 *
 * @author oleg
 */
public class DirectionButton extends JButton {

    private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2(null);
    boolean selecting = false;
    JMapPane jMapPane;
    CursorTool cursorTool;
    int count = 0;
    DirectPosition2D points[];
    Guide guide;
    Graphics2D graphics2D;
    CoordinateReferenceSystem dataCRS;
    CoordinateReferenceSystem worldCRS;
    StyleFactory sfy;

    private void ViewStartFinishPoints(Point2D[] p) {


        SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();

        //set the name
        b.setName("Flag");
        try {
            b.setCRS(CRS.decode("EPSG:32637"));
        } catch (NoSuchAuthorityCodeException ex) {
            Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FactoryException ex) {
            Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
        }
        //add some properties
        b.add("name", String.class);
        b.add("location", Point.class);
        b.add("classification", Integer.class);
        b.add("height", Double.class);

        GeometryFactory gf = new GeometryFactory();

        //add a geometry property
        //build the type
        SimpleFeatureType type = b.buildFeatureType();

        SimpleFeatureCollection collection = new ListFeatureCollection(type);
        for (int i = 0; i < p.length; i++) {

            if (p[i].getX() == 0 && p[i].getY() == 0) {
                return;
            }
            try {
                //MathTransform transform = CRS.findMathTransform(DefaultGeographicCRS.WGS84, jMapPane.getMapContext().getCoordinateReferenceSystem());
                //DirectPosition2D d2 = new DirectPosition2D();
                //Coordinate c = new Coordinate();
                //JTS.transform(new Coordinate(points[i].getX(), points[i].getY()), c, transform);
                //d2.setLocation(c.x, c.y);
                SimpleFeatureBuilder sfb = new SimpleFeatureBuilder(type);
                sfb.add("myposition");
                sfb.add(gf.createPoint(new Coordinate(p[i].getX(), p[i].getY())));
                sfb.add(21);
                sfb.add(222);
                SimpleFeature sf = sfb.buildFeature("one");
                collection.add(sf);
            } catch (Exception ex) {
                Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        System.out.println("точки похожи на правду");


        MyStyle ms = new MyStyle(MyStyle.GeomType.POINT);
        Rule rule = ms.createRuleAdv(Color.yellow, Color.RED, 5.0f);
        FeatureTypeStyle fts = sfy.createFeatureTypeStyle();
        fts.rules().add(rule);

        Style style = sfy.createStyle();
        style.featureTypeStyles().add(fts);
        jMapPane.getMapContext().addLayer(collection, style);
        try {
            jMapPane.getMapContext().setCoordinateReferenceSystem(CRS.decode("EPSG:32637"));
        } catch (NoSuchAuthorityCodeException ex) {
            Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FactoryException ex) {
            Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    String btnname;
    static Object id = 0;
    final DirectionImprovement improvement;

    JMapFrame mapFrame;
    SimpleFeatureSource featureSource;
    CoordinateReferenceSystem oldCRS;
    CoordinateReferenceSystem newCRS;

    DirectionButton(JMapFrame mapFrame, SimpleFeatureSource featureSource, final JMapPane jMapPane, final Guide guide, StyleFactory sf, String btnname, DirectionImprovement improvementIn, CoordinateReferenceSystem oldCRS, CoordinateReferenceSystem newCRS) {
        this.oldCRS=oldCRS;
        this.newCRS=newCRS;
        this.mapFrame=mapFrame;
        this.featureSource=featureSource;
        this.setAction(new GuideAction(btnname));
        this.jMapPane = jMapPane;
        this.btnname = btnname;
        this.guide = guide;
        this.sfy = sf;
        graphics2D = (Graphics2D) this.getGraphics();
        SimpleFeature simpleFeatureStart[];
        SimpleFeature simpleFeatureFinish[];
        points = new DirectPosition2D[2];

        this.improvement = improvementIn;

        cursorTool = new CursorTool() {

            @Override
            public void onMouseMoved(MapMouseEvent ev) {
                super.onMouseMoved(ev);

                if (selecting) {
                    if (count == 2) {
                        count = 0;
                    }
                    Graphics2D g2 = (Graphics2D) jMapPane.getGraphics();
                    jMapPane.repaint(ev.getX() - 10, ev.getY() - 10, 20, 20);
                    Point2D p = new Point2D.Double(ev.getX(), ev.getY());
                    points[count] = ev.getMapPosition();
                    if (points[count].getX() == 0) {
                        return;
                    }
                    try {
                        SimpleFeatureCollection selectedFeatures = getSelectedFeatures(p);
                        SimpleFeatureIterator iter = selectedFeatures.features();
                        try {
                            while (iter.hasNext()) {
                                SimpleFeature feature = iter.next();
                                Geometry geom = (MultiLineString) feature.getDefaultGeometry();

                                //MathTransform transform = CRS.findMathTransform(jMapPane.getMapContext().getCoordinateReferenceSystem(), CRS.decode("EPSG:4326"), true);
                                //DirectPosition2D d2 = new DirectPosition2D();
                                //transform.transform(points[count], d2);

                                Point2D closestPositionOnTrack = SomeMath.getClosestPositionOnTrack(points[count].getX(), points[count].getY(), geom);
                                points[count].setLocation(closestPositionOnTrack);
                                System.out.println("   " + feature.getIdentifier() + " " + points[count].getX() + points[count].getY());


                                g2.drawOval(ev.getX() - 2, ev.getY() - 2, 5, 5);
                            }

                        } finally {
                            iter.close();
                        }
                    } catch (FactoryException ex) {
                        Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (TransformException ex) {
                        Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
                    }

                }
            }

            @Override
            public void onMouseClicked(MapMouseEvent ev) {
                super.onMouseClicked(ev);
                System.out.println("" + ev.getButton());
                if (selecting) {
                    Point2D p = new Point2D.Double(ev.getX(), ev.getY());
                    points[count] = ev.getMapPosition();
                    try {
                        SimpleFeatureCollection selectedFeatures = getSelectedFeatures(p);
                        SimpleFeatureIterator iter = selectedFeatures.features();
                        try {
                            while (iter.hasNext()) {
                                SimpleFeature feature = iter.next();
                                Geometry geom = (MultiLineString) feature.getDefaultGeometry();

                                Graphics2D graphics = (Graphics2D) jMapPane.getGraphics();
                                graphics.setColor(Color.GREEN);
                                Coordinate[] coordinates = geom.getCoordinates();

                                AffineTransform worldToScreenTransform = jMapPane.getWorldToScreenTransform();
                                DirectPosition2D src = new DirectPosition2D();
                                DirectPosition2D dst = new DirectPosition2D();
                                src.setLocation(coordinates[0].x, coordinates[0].y);
                                worldToScreenTransform.transform(src, dst);
                                graphics.drawString("start", (int) dst.x, (int) dst.y);
                                System.out.println("transformed " + dst.x + ";" + dst.y);
                                id = (feature.getProperty("ID").getValue());
                                //если нажата правая клавиша мыши
                                if (ev.getButton() == 3) {
                                    final ProgressWindow progress = new ProgressWindow(null);
                                    progress.setTitle("Reversing feature geometry");


                                    FeatureSource featureSource = jMapPane.getMapContext().getLayers()[0].getFeatureSource();
                                    FeatureCollection features = featureSource.getFeatures();
                                    features.accepts(new AbstractFeatureVisitor() {

                                        @Override
                                        public void visit(Feature feature2) {
                                            Long str = (Long) feature2.getProperty("ID").getValue();
                                            //System.out.println(str+"-"+(Long)id);
                                            if (((Long) (feature2.getProperty("ID").getValue())).equals(id)) {
                                                System.out.println("feature2 найдено");
                                                SimpleFeature f = (SimpleFeature) feature2;
                                                Geometry geom = (MultiLineString) f.getDefaultGeometry();
                                                System.out.println("old geom: " + geom.toString());
                                                Geometry reverse = geom.reverse();
                                                System.out.println("new geom: " + reverse.toString());
                                                f.setDefaultGeometry(reverse);
                                                Collection<Property> properties = feature2.getProperties();
                                                Iterator<Property> iterator = properties.iterator();
                                                while (iterator.hasNext()) {
                                                    Property next = iterator.next();
                                                    System.out.println(next.getName() + ":" + next.getValue());
                                                }
                                                feature2.getProperty("the_geom").setValue(reverse);
                                                improvement.add(f);
                                                System.out.println("Reversed successfully!");
                                            }
                                        }
                                    }, progress);
                                }
                            }

                        } catch (IOException ex) {
                            Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
                        } finally {
                            iter.close();
                        }
                    } catch (FactoryException ex) {
                        Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (TransformException ex) {
                        Logger.getLogger(DirectionButton.class.getName()).log(Level.SEVERE, null, ex);
                    }

                }
            }
        };

    }

    class GuideAction extends SafeAction {

        public GuideAction() {
            super(btnname);
        }

        public GuideAction(String btnname) {
            super(btnname);
        }

        @Override
        public void action(ActionEvent e) throws Throwable {
            if (selecting) {
                selecting = false;

            } else {
                selecting = true;
                jMapPane.setCursorTool(cursorTool);
                if (count == 0) {
                    points = new DirectPosition2D[2];
                }
                //count = 0;
                if (graphics2D != null) {
                    graphics2D.setBackground(Color.yellow);
                }
            }
            System.out.println("" + selecting);
        }
    }

    public SimpleFeatureCollection getSelectedFeatures(Point2D screenPos) throws FactoryException, TransformException {

        Rectangle screenRect = new Rectangle((int) (screenPos.getX() - 2), (int) (screenPos.getY() - 2), 5, 5);

        /*
         * Transform the screen rectangle into bounding box in the coordinate
         * reference system of our map context. Note: we are using a naive method
         * here but GeoTools also offers other, more accurate methods.
         */
        SimpleFeatureType schema = featureSource.getSchema();


        AffineTransform screenToWorld = mapFrame.getMapPane().getScreenToWorldTransform();
        Rectangle2D worldRect = screenToWorld.createTransformedShape(screenRect).getBounds2D();


        ReferencedEnvelope bbox = new ReferencedEnvelope(
                worldRect,
                newCRS);
        // transform from world to target CRS

        //Не работает из-за новой карты
        CoordinateReferenceSystem targetCRS = schema.getCoordinateReferenceSystem();
        //CoordinateReferenceSystem targetCRS = CRS.decode("EPSG:32637");
        String geometryAttributeName = schema.getGeometryDescriptor().getLocalName();
        bbox = bbox.transform(targetCRS, true, 10);

        /*
         * Create a Filter to select features that intersect with
         * the bounding box
         */
        Filter filter = ff.intersects(ff.property(geometryAttributeName), ff.literal(bbox));

        /*
         * Use the filter to identify the selected features
         */
        try {
            SimpleFeatureCollection selectedFeatures =
                    featureSource.getFeatures(filter);
            selectedFeatures = (SimpleFeatureCollection) mapFrame.getMapContext().getLayer(0).getFeatureSource().getFeatures(filter);

            if (selectedFeatures.size() == 0) {
                System.out.println("под кликом ничего нет");
            }
            return selectedFeatures;

        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }


    }
}
